﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="IGame.cs" company="SingularityShift">
//   Copyright (c) 2010 SingularityShift.com
// </copyright>
// <author>Ben McClure</author>
// <email>ben@singularityshift.com</email>
// <date>2010-11-30</date>
// <summary>
//   A public interface which defines an object representing a game
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace GameLib.Games
{
    #region Using Directives

    using System;

    using GameLib.Games.CompositeModel;
    using GameLib.Games.Util;

    #endregion

    /// <summary>
    /// A base, generic interface to an object representing a game. 
    /// </summary>
    /// <remarks>
    /// Ben McClure, 11/30/2010. 
    /// </remarks>
    /// <typeparam name="T">
    /// Specifies the type of <see cref="IMod"/> this game uses. If unsure, just use the base
    /// interface, <see cref="IMod"/>. 
    /// </typeparam>
    public interface IGame<T> : ICloneable
        where T : IMod
    {
        #region Events

        /// <summary>
        /// Thrown whenever anything about a game changes
        /// </summary>
        event EventHandler<GameChangedEventArgs> GameChanged;

        #endregion

        #region Properties

        /// <summary> 
        /// Gets the list of <see cref="IMod">IMods</see> currently active in this game.
        /// </summary>
        /// <remarks>May invariably be the same as the <see cref="InstalledMods"/> for games or implementations that do
        /// not support mod enabling/disabling.</remarks>
        /// <value> The active mods. </value>
        IModCollection<T> ActiveMods { get; }

        /// <summary>   
        /// Gets or sets the directory (relative to<see cref="GameDir"/>or absolute) where the game executable exists. 
        /// </summary>
        /// <value> The pathname of the bin directory. </value>
        string BinDir { get; set; }

        /// <summary> 
        /// <para>Gets or sets the path of the game's primary configuration file, if a game supports one.</para>
        /// <para>The file format is dependent on the game, so is not specified in this API. Typically, this could be a
        /// text file, Ini file, or XML file, or some other possibly-proprietary file type.</para> 
        /// <remarks>In the future, a game configuration file could become an extendable interface in itself</remarks>
        /// </summary>
        /// <value> The configuration file. </value>
        string ConfigFile { get; set; }

        /// <summary>
        /// Gets or sets the top-level directory where the game's data files are stored. This can be absolute or relative to the <see cref="GameDir"/>.
        /// </summary>
        string DataDir { get; set; }

        /// <summary> 
        /// <para>Gets or sets a directory for moving inactive mod files to, when appropriate. This should generally
        /// only be used when the game itself does not support "disabling" an installed mod by default.</para>
        /// <para>If this is not blank, the <see cref="DisableMod"/> function should attempt to move the mod file here,
        /// and the <see cref="EnableMod"/> function should attempt to move the mod file from here if it doesn't already
        /// exist in the <see cref="ModDir"/>.
        /// </para> 
        /// </summary>
        /// <value> The pathname of the disabled mod directory. </value>
        string DisabledModDir { get; set; }

        /// <summary> 
        /// Gets or sets the filename of the executable in the <see cref="BinDir"/>, or the absolute path to the
        /// executable. 
        /// </summary>
        /// <value> The executable. </value>
        string Exe { get; set; }

        /// <summary>   Gets or sets the pathname of the game directory. </summary>
        /// <value> The pathname of the game directory. </value>
        string GameDir { get; set; }

        /// <summary>   
        /// <para>Gets a string containing the game's id (usually the same as its <see cref="Title"/>, or a shortened
        /// version of it).</para>
        /// <para>Ideally this should be unique in order to look up a game by its ID.</para> 
        /// </summary>
        /// <value> The identifier. </value>
        string Id { get; }

        /// <summary> Gets the list of <see cref="IMod">IMods</see> currently installed for this game. </summary>
        /// <remarks> 
        /// This often does NOT represent the <see cref="IMod">IMods</see> that are actually active in a game. This is
        /// the <see cref="IMod">IMods</see> that are installed on the computer and available for the game (if they are
        /// enabled). 
        /// </remarks>
        /// <value> The installed mods. </value>
        IModCollection<T> InstalledMods { get; }

        /// <summary>   
        /// Gets or sets the directory where game mods are stored. This can be absolute or relative to the
        /// <see cref="GameDir"/>. 
        /// </summary>
        /// <value> The pathname of the modifier directory. </value>
        string ModDir { get; set; }

        /// <summary>   Gets or sets the game's full title. </summary>
        /// <value> The title. </value>
        string Title { get; set; }

        #endregion

        #region Public Methods

        /// <summary>
        /// <para>
        /// Creates a new, blank <see cref="IMod"/> instance of this game's type.
        /// </para>
        /// <para>
        /// This always sets the <see cref="IMod.Owner">Owner</see> property of the new <see cref="IMod"/> to this
        /// game's instance.
        /// </para>
        /// </summary>
        /// <returns>
        /// The new, blank <see cref="IMod"/> instance. 
        /// </returns>
        T CreateMod();

        /// <summary>
        /// When implemented (or supported by the game), this method disables (or deactivates) an installed<see cref="IMod"/>in the game.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This method should not physically uninstall the<see cref="IMod"/>.
        /// </para>
        /// <para>
        /// When uninstalling an<see cref="IMod"/>, if it is not already disabled this method should be called.
        /// </para>
        /// <para>
        /// If the<see cref="IMod"/>is not installed, this method should throw a<see cref="ModNotInstalledException"/>.
        /// </para>
        /// <para>
        /// If the<see cref="IMod"/>is installed but not currently enabled, this method should silently do
        /// nothing and report success (it's already disabled).
        /// </para>
        /// </remarks>
        /// <param name="mod">
        /// The<see cref="IMod"/>to deactivate.
        /// </param>
        void DisableMod(T mod);

        /// <summary>
        /// When implemented (or supported by the game), this method enables or activates an installed <see cref="IMod"/> in the game.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This method should not physically install the <see cref="IMod"/>; that should already be done.
        /// </para>
        /// <para>
        /// If the <see cref="IMod"/> is not installed, this method should throw a <see cref="ModNotInstalledException"/>.
        /// </para>
        /// <para>
        /// If the <see cref="IMod"/> is already enabled, this mod should do nothing and simply return success.
        /// </para>
        /// </remarks>
        /// <param name="mod">
        /// The <see cref="IMod"/> object describing the mod to activate.
        /// </param>
        void EnableMod(T mod);

        /// <summary>
        /// Gets the <see cref="ActiveMods"/> of this game.
        /// </summary>
        /// <returns>
        /// The <see cref="ActiveMods"/> property of the game.
        /// </returns>
        IModCollection<T> GetActiveMods();

        /// <summary>
        /// Gets a collection of currently-installed <see cref="IMod">IMods</see> of this game. 
        /// </summary>
        /// <returns>
        /// The <see cref="InstalledMods"/> property of the game. 
        /// </returns>
        IModCollection<T> GetInstalledMods();

        /// <summary>
        /// Determines whether the provided <see cref="IMod"/> is active within the game
        /// </summary>
        /// <param name="mod">
        /// The <see cref="IMod"/> to check for
        /// </param>
        /// <returns>
        /// A boolean indicating whether the mod is active
        /// </returns>
        bool IsActive(T mod);

        /// <summary>
        /// Determines if this game is currently installed on the system. 
        /// </summary>
        /// <returns>
        /// A boolean indicating whether the game is installed. 
        /// </returns>
        bool IsInstalled();

        /// <summary>
        /// Determines whether the provided <see cref="IMod"/> is installed in the game. 
        /// </summary>
        /// <param name="mod">
        /// The <see cref="IMod"/> to check for. 
        /// </param>
        /// <returns>
        /// A boolean indicating whether the <see cref="IMod"/> is installed. 
        /// </returns>
        bool IsInstalled(T mod);

        /// <summary>
        /// Sets the active<see cref="IMod">IMods</see>to be the same as the provided<see cref="IModCollection"/> 
        /// </summary>
        /// <param name="mods">
        /// The<see cref="IModCollection"/>containing the mods to indicate as active.
        /// </param>
        void SetActiveMods(IModCollection<T> mods);

        /// <summary>
        /// Sets the installed <see cref="IMod">IMods</see> to be the same as the provided <see cref="IModCollection"/>
        /// </summary>
        /// <param name="mods">
        /// The <see cref="IModCollection"/> containing the mods to indicate as installed
        /// </param>
        void SetInstalledMods(IModCollection<T> mods);

        #endregion
    }
}